package com.king.hessian;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.collections.keyvalue.MultiKey;
import org.apache.commons.lang.ArrayUtils;

import com.qd.util.ObjectUtils;

/**
 * 用于处理@Cacheable标识的接口
 */
public class CacheableMethodInterceptor implements MethodInterceptor {

    private final Map<Object, Object> cache = new ConcurrentHashMap<>();

    private final MethodInterceptor inner;

    public CacheableMethodInterceptor(MethodInterceptor inner) {
        this.inner = inner;
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        Cacheable cacheable = method.getAnnotation(Cacheable.class);
        if (cacheable != null) {
            Object[] args = invocation.getArguments();
            Object key = buildKey(method, args);
            Object cachedObject = cache.get(key);
            if (cachedObject != null) {
                return ObjectUtils.unwrapNull(cachedObject);
            }
            Object object = inner.invoke(invocation);
            cache.put(key, ObjectUtils.wrapNull(object));
            return object;
        } else {
            return inner.invoke(invocation);
        }
    }

    private Object buildKey(Method method, Object[] args) {
        if (ArrayUtils.isEmpty(args)) {
            return method;
        }
        else {
            Object[] array = new Object[args.length + 1];
            array[0] = method;
            System.arraycopy(args, 0, array, 1, args.length);
            return new MultiKey(array);
        }
    }
}
